﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TvdP;

namespace TvdP
{
    [TestClass]
    public partial class AdapterUnitTest
    {
        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void VerifyAdapter_throws_ArgumentNullException_when_adapter_is_null()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)null);           
        }

        public class Class1 { }

        public class Class2 { }

        public class Class3 { }

        public class Class4 { }

        public class Class5 { }

        [TestMethod]
        public void VerifyAdapter_accepts_adapter_delegate_of_proper_form_class1_to_class2()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1, Class2>(c1 => new Class2()));
        }

        [TestMethod]
        public void VerifyAdapter_accepts_adapter_delegate_of_proper_form_class1_2_3_4_to_class5()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1, Class2, Class3, Class4, Class5>((c1, c2, c3, c4) => new Class5()));
        }


        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_no_return_type()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Action<object>(o => { }));
        }

        public struct X1 { };

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_value_type_as_return_type()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1, X1>(c1 => new X1()));
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_no_input_parameters()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1>(() => new Class1()));
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_input_parameter_of_value_type()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<X1, Class1>(x1 => new Class1()));
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_fourth_input_parameter_of_value_type()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1, Class2, Class3, X1, Class4>((c1, c2, c3, x1) => new Class4()));
        }

        public class Class1b : Class1 { }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_return_value_of_type_assignable_from_type_of_first_input_parameter()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1b, Class1>(c1b => new Class1()));
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_return_value_of_type_assignable_from_type_of_third_input_parameter()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class2,Class3,Class1b,Class4,Class1>((c2, c3, c1b, c4) => new Class1()));
        }

        [TestMethod]
        public void VerifyAdapter_accepts_adapter_delegate_of_proper_form_class1_to_class2_where_class1_assignable_from_class2()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched((Delegate)new Func<Class1, Class1b>(c1 => new Class1b()));
        }

        delegate Class2 _Adapter_with_input_parameter_by_refref(ref Class1 c1);

        Class2 _adapter_with_input_parameter_by_ref(ref Class1 c1)
        { return null; }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_input_parameter_by_ref()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched(
                (_Adapter_with_input_parameter_by_refref)
                    delegate(ref Class1 c1)
                    { return null;}
            );
        }

        delegate Class4 _Adapter_with_second_parameter_which_is_output(Class1 c1, out Class2 c2, Class3 c3);

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void VerifyAdapter_throws_ArgumentException_when_adapter_delegate_has_second_parameter_which_is_output()
        {
            Adapter.VerifiedThatRequiredSignatureIsMatched(
                (_Adapter_with_second_parameter_which_is_output)
                    delegate(Class1 c1, out Class2 c2, Class3 c3) 
                    { c2 = null; return null; }
            );
        }

    }
}
